package view

import (
	"encoding/binary"
	"fmt"
	"math"
)

/**
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
*/

/*
*
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;  ConstantValue_attribute 结构的 attribute_length 项的值固定为 2
u2 constantvalue_index;
}
*/
type ConstantValueAttr struct {
	Attribute
	ConstantValueIndex uint16
	Value              Constant
}

func (self *ConstantValueAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.ConstantValueIndex = self.Data.readUInt16()
	self.Value = cp.ConstantList[self.ConstantValueIndex-1]
	return self
}

/*
*
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;

	 {     u2 start_pc;
			u2 end_pc;
			u2 handler_pc;
			u2 catch_type;
	} exception_table[exception_table_length];

u2 attributes_count;
attribute_info attributes[attributes_count];
}
*/
type CodeAttr struct {
	Attribute
	MaxStack             uint16
	MaxLocals            uint16
	CodeLength           uint32
	CodeList             []uint8
	ExceptionTableLength uint16
	ExceptionTableList   []ExceptionTable
	AttributeCount       uint16
	AttributeInfoList    []AttributeInfo
}

type ExceptionTable struct {
	StartPc   uint16
	EndPc     uint16
	HandlerPc uint16
	CatchType uint16
}

func (self *CodeAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.MaxStack = self.Data.readUInt16()
	self.MaxLocals = self.Data.readUInt16()
	self.CodeLength = self.Data.readUInt32()
	self.CodeList = self.Data.readUInt8s(int(self.CodeLength))
	self.ExceptionTableLength = self.Data.readUInt16()
	if self.ExceptionTableLength > 0 {
		self.ExceptionTableList = make([]ExceptionTable, self.ExceptionTableLength)
		for i := 0; i < len(self.ExceptionTableList); i++ {
			self.ExceptionTableList[i] = NewExceptionTable(self.Data, cp)
		}
	}

	self.AttributeCount = self.Data.readUInt16()
	if self.AttributeCount > 0 {
		self.AttributeInfoList = make([]AttributeInfo, self.AttributeCount)
		for i := 0; i < int(self.AttributeCount); i++ {
			self.AttributeInfoList[i] = NewAttributeInfoFromBytes(self.Data, cp)
		}
	}
	return self
}

func NewExceptionTable(data *AttributeData, cp ConstantPoolInfo) ExceptionTable {
	e := ExceptionTable{}
	e.StartPc = data.readUInt16()
	e.EndPc = data.readUInt16()
	e.HandlerPc = data.readUInt16()
	e.CatchType = data.readUInt16()
	return e
}

func (self *AttributeData) readUInt16() uint16 {
	b2 := binary.BigEndian.Uint16(self.data[self.pos : self.pos+2])
	self.pos += 2
	return b2
}

func (self *AttributeData) readUInt32() uint32 {
	b2 := binary.BigEndian.Uint32(self.data[self.pos : self.pos+4])
	self.pos += 4
	return b2
}

func (self *AttributeData) readUInt64() uint32 {
	b2 := binary.BigEndian.Uint32(self.data[self.pos : self.pos+8])
	self.pos += 8
	return b2
}

func (self *AttributeData) readUInt8() uint8 {
	b2 := self.data[self.pos]
	self.pos += 1
	return b2
}

func (self *AttributeData) readUInt8s(n int) []uint8 {
	b2 := self.data[self.pos : self.pos+n]
	self.pos += n
	return b2
}

/*
*
方法的行号信息
*/
type LineNumberTableAttr struct {
	Attribute
	LineTableLength uint16
	LineNumber      []LineNumberInfo
}

type LineNumberInfo struct {
	StartPc uint16
	LineNo  uint16
}

func (self *LineNumberTableAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.LineTableLength = self.Data.readUInt16()
	if self.LineTableLength > 0 {
		self.LineNumber = make([]LineNumberInfo, self.LineTableLength)
		for i := 0; i < int(self.LineTableLength); i++ {
			self.LineNumber[i] = NewLineNumber(self.Data)
		}
	}
	return self
}

func NewLineNumber(data *AttributeData) LineNumberInfo {
	startPc := data.readUInt16()
	lineNo := data.readUInt16()
	return LineNumberInfo{startPc, lineNo}
}

type LocalVariableTableAttr struct {
	Attribute
	LocalVariableTableLength uint16
	LocalVariableTable       []LocalVariableTableInfo
}

type LocalVariableTableInfo struct {
	// 变量开始生效的行
	StartPc uint16
	// 变量影响范围
	Length uint16
	// 变量名称
	LocalVariableNameIndex uint16
	LocalVariableName_     Constant
	// 变量类型描述
	LocalVariableDescriptorIndex uint16
	LocalVariableDescriptor_     Constant
	// 序号
	LocalVariableIndex uint16
}

func (self *LocalVariableTableAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.LocalVariableTableLength = self.Data.readUInt16()
	if self.LocalVariableTableLength > 0 {
		self.LocalVariableTable = make([]LocalVariableTableInfo, self.LocalVariableTableLength)
		for i := 0; i < int(self.LocalVariableTableLength); i++ {
			self.LocalVariableTable[i] = NewLocalVariableTable(self.Data, cp)
		}
	}
	return self
}

func NewLocalVariableTable(data *AttributeData, cp ConstantPoolInfo) LocalVariableTableInfo {
	startPc := data.readUInt16()
	Length := data.readUInt16()
	LocalVariableNameIndex := data.readUInt16()
	LocalVariableDescriptorIndex := data.readUInt16()
	LocalVariableName_ := cp.ConstantList[LocalVariableNameIndex-1]
	LocalVariableDescriptor_ := cp.ConstantList[LocalVariableDescriptorIndex-1]
	LocalVariableIndex := data.readUInt16()
	return LocalVariableTableInfo{startPc, Length, LocalVariableNameIndex, LocalVariableName_,
		LocalVariableDescriptorIndex, LocalVariableDescriptor_, LocalVariableIndex}
}

// StackMapTable 是 Java 字节码中的一种属性表，用于支持类型检查和异常处理。它记录了方法中操作数栈和局部变量区中类型的信息，用于验证和校验字节码。
type StackMapTableAttr struct {
	Attribute
	EntryLength uint16
	EntryList   []StackMapEntry
}

type StackMapEntry struct {
}

func (self *StackMapTableAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	// 太复杂了 我不是实现了 哎
	return self
}

type ExceptionTableAttr struct {
	Attribute
	ExceptionTableLength uint16
	ExceptionTableList   []uint16
	ExceptionTableList_  []Constant
}

func (self *ExceptionTableAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.ExceptionTableLength = self.Data.readUInt16()
	if self.ExceptionTableLength > 0 {
		self.ExceptionTableList = make([]uint16, self.ExceptionTableLength)
		self.ExceptionTableList_ = make([]Constant, self.ExceptionTableLength)
		for i := 0; i < len(self.ExceptionTableList); i++ {
			self.ExceptionTableList[i] = self.Data.readUInt16()
			self.ExceptionTableList_[i] = cp.ConstantList[self.ExceptionTableList[i]-1]
		}
	}
	return self
}

type LocalVariableTypeTableAttr struct {
	Attribute
	LocalVariableTypeTableLength uint16
	LocalVariableTypeTableList   []LocalVariableTypeTableInfo
}

type LocalVariableTypeTableInfo struct {
	// 变量开始生效的行
	StartPc uint16
	// 变量影响范围
	Length uint16
	// 变量名称
	LocalVariableTypeNameIndex uint16
	LocalVariableTypeName_     Constant
	SignatureIndex             uint16
	Signature_                 Constant
	// 序号
	LocalVariableTypeIndex uint16
}

func (self *LocalVariableTypeTableAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.LocalVariableTypeTableLength = self.Data.readUInt16()
	if self.LocalVariableTypeTableLength > 0 {
		self.LocalVariableTypeTableList = make([]LocalVariableTypeTableInfo, self.LocalVariableTypeTableLength)
		for i := 0; i < int(self.LocalVariableTypeTableLength); i++ {
			self.LocalVariableTypeTableList[i] = NewLocalVariableTypeTable(self.Data, cp)
		}
	}
	return self
}

func NewLocalVariableTypeTable(data *AttributeData, cp ConstantPoolInfo) LocalVariableTypeTableInfo {
	startPc := data.readUInt16()
	Length := data.readUInt16()
	LocalVariableNameIndex := data.readUInt16()
	LocalVariableDescriptorIndex := data.readUInt16()
	LocalVariableName_ := cp.ConstantList[LocalVariableNameIndex-1]
	LocalVariableDescriptor_ := cp.ConstantList[LocalVariableDescriptorIndex-1]
	LocalVariableIndex := data.readUInt16()
	return LocalVariableTypeTableInfo{startPc, Length, LocalVariableNameIndex, LocalVariableName_,
		LocalVariableDescriptorIndex, LocalVariableDescriptor_, LocalVariableIndex}
}

type SignatureAttr struct {
	Attribute
	SignatureIndex uint16
}

func (self *SignatureAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.SignatureIndex = self.Data.readUInt16()
	return self
}

type SourceFileAttr struct {
	Attribute
	SourceFileIndex uint16
	SourceFile_     Constant
}

func (self *SourceFileAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.SourceFileIndex = self.Data.readUInt16()
	self.SourceFile_ = cp.ConstantList[self.SourceFileIndex-1]
	return self
}

type RuntimeVisibleAnnotationsAttr struct {
	Attribute
	AnnotationNumber uint16
	AnnotationList   []AnnotationInfo
}
type AnnotationInfo struct {
	TypeIndex uint16
	pairNum   uint16
	pairs     []Pair
}

type Pair struct {
	PairIndex uint16
	PairValue interface{}
}

func (self *RuntimeVisibleAnnotationsAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {

	self.AnnotationNumber = self.Data.readUInt16()

	if self.AnnotationNumber > 0 {
		self.AnnotationList = make([]AnnotationInfo, self.AnnotationNumber)
		for i := 0; i < int(self.AnnotationNumber); i++ {
			self.AnnotationList[i] = NewAnnotationInfo(self.Data, cp)
		}
	}
	return self
}

func NewAnnotationInfo(data *AttributeData, cp ConstantPoolInfo) AnnotationInfo {
	a := &AnnotationInfo{}
	a.TypeIndex = data.readUInt16()
	a.pairNum = data.readUInt16()
	if a.pairNum > 0 {
		a.pairs = make([]Pair, a.pairNum)
		for i := 0; i < len(a.pairs); i++ {
			a.pairs[i] = NewPair(data, cp)
		}
	}
	return *a
}

func NewPair(data *AttributeData, cp ConstantPoolInfo) Pair {
	p := &Pair{}
	p.PairIndex = data.readUInt16()
	p.PairValue = getValue(p.PairIndex, data)
	return *p
}

func getValue(typeIndex uint16, data *AttributeData) interface{} {
	switch typeIndex {
	case 0x0000: // BYTE
		return data.readUInt8()
	case 0x0001: // CHAR
		return rune(data.readUInt8())
	case 0x0002: // DOUBLE
		return math.Float32frombits(data.readUInt64())
	case 0x0003: // FLOAT
		return math.Float32frombits(data.readUInt32())
	case 0x0004: // INT
		return int32(data.readUInt32())
	case 0x0005: // LONG
		return data.readUInt64()
	case 0x0006: // SHORT
		return int16(data.readUInt16())
	case 0x0007: // TRUE_OR_FALSE (boolean)
		return (data.readUInt8()&0x01 != 0)
	default: // OTHER or PRIMITIVE_ Wrappers and Class are handled as interface{} with string name of the type in this example.
		return fmt.Sprintf("%v", string(data.pos)) // string conversion for other types (e.g., Strings) or wrappers for primitive types (e.g., Integer, Boolean).
	}
}

type InnerClassesAttr struct {
	Attribute
	NumberOfClasses uint16
	ClassList       []InnerClassInfo
}

type InnerClassInfo struct {
	InnerClassInfoIndex   uint16
	OuterClassInfoIndex   uint16
	InnerNameIndex        uint16
	innerClassAccessFlags uint16
}

func (self *InnerClassesAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	self.NumberOfClasses = self.Data.readUInt16()
	if self.NumberOfClasses > 0 {
		self.ClassList = make([]InnerClassInfo, self.NumberOfClasses)
		for i := 0; i < int(self.NumberOfClasses); i++ {
			self.ClassList[i] = NewInnerClass(self.Data, cp)
		}
	}
	return self
}

func NewInnerClass(data *AttributeData, cp ConstantPoolInfo) InnerClassInfo {
	ic := &InnerClassInfo{}
	ic.InnerNameIndex = data.readUInt16()
	ic.OuterClassInfoIndex = data.readUInt16()
	ic.InnerClassInfoIndex = data.readUInt16()
	ic.innerClassAccessFlags = data.readUInt16()
	return *ic
}

type BootstrapMethodsAttr struct {
	Attribute
}

func (self *BootstrapMethodsAttr) readAttrInfo(cp ConstantPoolInfo) AttributeInfo {
	return self
}
